import { 
  AxesHelper,
  BackSide,
  Float32BufferAttribute,
  HemisphereLight,
  Mesh,
  MeshBasicMaterial,
  PerspectiveCamera, 
  QuadraticBezierCurve3, 
  Scene, 
  TorusKnotGeometry, 
  TubeBufferGeometry, 
  Vector2, 
  Vector3, 
  WebGLRenderer 
} from "three"
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'
import { RenderPass } from 'three/examples/jsm/postprocessing/RenderPass'
import { UnrealBloomPass } from 'three/examples/jsm/postprocessing/UnrealBloomPass'
import { EffectComposer } from 'three/examples/jsm/postprocessing/EffectComposer'
import { interpolateHsl } from 'd3-interpolate'
import TWEEN from '@tweenjs/tween.js'
import stats from '../utils/stats'

const scene = new Scene()
const camera = new PerspectiveCamera(45, window.innerWidth/window.innerHeight, 0.1, 1000)
// 不能设置为0
camera.position.set(340, 105, -180)

const renderer = new WebGLRenderer({ antialias: true })
renderer.setPixelRatio(window.devicePixelRatio)
renderer.setClearColor(0x000000)
renderer.setSize(window.innerWidth, window.innerHeight)

document.body.appendChild(renderer.domElement)

new OrbitControls(camera, renderer.domElement)

// 添加坐标系
const axes = new AxesHelper(100)
scene.add(axes)

const light = new HemisphereLight(0xffffff, 0xcccccc, 1)
scene.add(light)

const renderScene = new RenderPass(scene, camera)
const bloomPass = new UnrealBloomPass(
  new Vector2(window.innerWidth, window.innerHeight),
  1.5,
  0.4,
  0.85
)
bloomPass.threshold = 0.3
bloomPass.strength = 2
bloomPass.radius = 0.3

const bloomComposer = new EffectComposer(renderer)
bloomComposer.addPass(renderScene)
bloomComposer.addPass(bloomPass)

for (let i = 0; i < 100; i++) {

  // 生成曲线
  const startVec = new Vector3(300 * Math.random(), 0, -150 + 300 * Math.random())
  const controlVec = new Vector3(-200, 0, 20)
  const endVec = new Vector3(-300, 0, 300 + Math.random() * 50)
  const curve = new QuadraticBezierCurve3(startVec, controlVec, endVec)

  // 管道缓冲几何体
  const geometry = new TubeBufferGeometry(curve, 20, 0.1 + Math.random(), 3, false)
  // 
  const material = new MeshBasicMaterial({ 
    // 使用顶点着色
    vertexColors: true, 
    // 渲染正面
    side: BackSide
  })

  const colorsArr = ['#ffff00', '#00ffff']
  const count = geometry.attributes.position.count
  const rgbInterpolate = interpolateHsl(colorsArr[i % colorsArr.length], '#000000')
  const colorArr = new Array(count)

  for (let i = 0; i < count; i++) {
    const t = i / count
    const rgb = rgbInterpolate(t)
    const rgbVal = rgb.match(/\d+/g)

    const r = Number(rgbVal[0]) / 255
    const g = Number(rgbVal[1]) / 255
    const b = Number(rgbVal[2]) / 255

    colorArr[3 * i] = r
    colorArr[3 * i + 1] = g
    colorArr[3 * i + 2] = b
  }

  geometry.setAttribute('color', new Float32BufferAttribute(colorArr, 3))

  const mesh = new Mesh(geometry, material)
  scene.add(mesh)

  lightMove(mesh, colorArr, count)
}

function lightMove(mesh: Mesh, colorArr: number[], count: number): void {
  let tween = new TWEEN
    .Tween({value: 0})
    .to({value: 1}, 2000 * Math.random())
    .onUpdate(val => {
      const anchor = Number((val.value * count).toFixed(0))
      const b = colorArr.slice(anchor * 3)
      const f = colorArr.slice(0, anchor * 3)
      const newColorArr: number[] = ([] as any).concat(b, f)

      ;(mesh.geometry as TubeBufferGeometry).setAttribute('color', new Float32BufferAttribute(newColorArr, 3))
    })

  tween.repeat(Infinity)
  tween.start()
}

const animate = function(time) {
  TWEEN.update(time)
  stats.update()

  bloomComposer.render()
  requestAnimationFrame(animate)
}

requestAnimationFrame(animate)